package org.hibernate.tool.schema.internal;

import java.lang.reflect.Field;
import java.util.Iterator;

import org.hibernate.boot.Metadata;
import org.hibernate.boot.model.relational.SqlStringGenerationContext;
import org.hibernate.dialect.Dialect;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.ColumnWrapper;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.Table;
import org.hibernate.mapping.TableWrapper;
import org.hibernate.mapping.Utils;

import com.kinyx.framework.db.annotation.Comment;
import com.kinyx.framework.db.annotation.Order;
import com.kinyx.framework.db.configs.CompatibilizerConfigs;
import com.kinyx.framework.enums.impl.ErrorCode1;
import com.kinyx.framework.exception.KRuntimeException;

/**
 * 1、读取自定义注解com.kinyx.framework.db.annotation.Comment，实现对表的注释。
 * 2、读取自定义注解com.kinyx.framework.db.annotation.Comment，实现对列的注释。
 * 3、读取自定义注解com.kinyx.framework.db.annotation.Order，实现对列的排序。
 */
public class StandardTableExtendExporter extends StandardTableExporter {

	private static final Boolean skip = CompatibilizerConfigs.StandardTableExtendExporter_skip;
	private static final Boolean tableComment = CompatibilizerConfigs.StandardTableExtendExporter_tableComment;
	private static final Boolean columnComment = CompatibilizerConfigs.StandardTableExtendExporter_columnComment;
	private static final Boolean columnOrder = CompatibilizerConfigs.StandardTableExtendExporter_columnOrder;

	public StandardTableExtendExporter(final Dialect dialect) { super(dialect); }

	@Override
	public String[] getSqlCreateStrings(final Table table, final Metadata metadata, final SqlStringGenerationContext context) {
		if (skip) { return super.getSqlCreateStrings(table, metadata, context); }

		if (!tableComment && !columnComment && !columnOrder) {
			return super.getSqlCreateStrings(table, metadata, context);
		}

		// 取当前表绑定的持久化类
		final PersistentClass entityBinding = Utils.getEntityBinding(table, metadata);
		// 取实体类
		final Class<?> entityClass = entityBinding.getMappedClass();

		final TableWrapper tableWrapper = new TableWrapper(table, entityClass);

		// 表注释
		if (tableComment) {
			final String kinyxComment = this.getComment(entityClass);
			final String hibernateComment = table.getComment();
			if ((hibernateComment == null) || (hibernateComment.length() == 0)) {
				// 没有设置hibernate注解值，则直接设置自定义注解值。
				table.setComment(kinyxComment);
			} else {
				// 设置了hibernate注解值，则进行校验。
				if ((kinyxComment != null) && (kinyxComment.length() != 0)) {
					if (!hibernateComment.equals(kinyxComment)) {
						throw new KRuntimeException(ErrorCode1.CODE_ERROR_51).param("className", entityClass.getName()).param("str1", kinyxComment).param("str2", hibernateComment);
					}
				}
			}
		}

		if (!columnComment && !columnOrder) {
			return super.getSqlCreateStrings(table, metadata, context);
		}

		// 列注释
		// 单一主键字段注释
		if (entityBinding.hasIdentifierProperty()) {
			Utils.toColumnWrapper(table, entityClass, entityBinding.getIdentifierProperty()).forEach(columnWrapper -> {
				this.handleColumnWrapper(columnWrapper);
				tableWrapper.addPKColumnWrapper(columnWrapper);
			});
		}
		// 联合主键字段注释
		if (entityBinding.hasIdentifierMapper()) {
			final Component identifierMapper = entityBinding.getIdentifierMapper();
			@SuppressWarnings("unchecked") // 查看源码得知，这个泛型并无问题。
			final Iterator<Property> identifierPropertyIterator = identifierMapper.getPropertyIterator();
			while (identifierPropertyIterator.hasNext()) {
				Utils.toColumnWrapper(table, entityClass, identifierPropertyIterator.next()).forEach(columnWrapper -> {
					this.handleColumnWrapper(columnWrapper);
					tableWrapper.addPKColumnWrapper(columnWrapper);
				});
			}
		}
		// 其它字段注释
		@SuppressWarnings("unchecked") // 查看源码得知，这个泛型并无问题。
		// getUnjoinedPropertyIterator方法返回值并不包含主键字段。
		final Iterator<Property> propertyIterator = entityBinding.getUnjoinedPropertyIterator();
		while (propertyIterator.hasNext()) {
			Utils.toColumnWrapper(table, entityClass, propertyIterator.next()).forEach(columnWrapper -> {
				this.handleColumnWrapper(columnWrapper);
				tableWrapper.addColumnWrapper(columnWrapper);
			});
		}

		if (columnOrder) {
			final Table sortedColumnsTable = tableWrapper.sortedColumnsTable();
			final String[] sqlStrings = super.getSqlCreateStrings(sortedColumnsTable, metadata, context);
			TableWrapper.afterGetSqlCreateStrings(table, sortedColumnsTable);
			return sqlStrings;
		}

		return super.getSqlCreateStrings(table, metadata, context);
	}

	private void handleColumnWrapper(final ColumnWrapper columnWrapper) {
		if (columnComment) { this.handleFieldComment(columnWrapper); }
		if (columnOrder) { this.handleFieldOrder(columnWrapper); }
	}

	// 列字段与主键字段在处理逻辑上是一致的
	private void handleFieldComment(final ColumnWrapper wrapper) {
		final Column column = wrapper.getColumn();
		final Field mappedField = wrapper.getField();

		final String kinyxColumnComment = this.getComment(mappedField);
		final String hibernateColumnComment = column.getComment();
		if ((hibernateColumnComment == null) || (hibernateColumnComment.length() == 0)) {
			// 没有设置hibernate注解值，则直接设置自定义注解值。
			column.setComment(kinyxColumnComment);
		} else {
			// 设置了hibernate注解值，则进行校验。
			if ((kinyxColumnComment != null) && (kinyxColumnComment.length() != 0)) {
				if (!hibernateColumnComment.equals(kinyxColumnComment)) {
					throw new KRuntimeException(ErrorCode1.CODE_ERROR_52).param("className", wrapper.getEntityClass().getName()).param("fieldName", mappedField.getName()).param("str1", kinyxColumnComment).param("str2", hibernateColumnComment);
				}
			}
		}
	}

	private void handleFieldOrder(final ColumnWrapper columnWrapper) {
		columnWrapper.setOrder(this.getOrder(columnWrapper.getField()));
	}

	// 取自定义注解值
	private String getComment(final Class<?> entityClass) {
		final Comment annotation = entityClass.getAnnotation(Comment.class);
		return annotation == null ? null : annotation.value();
	}

	// 取自定义注解值
	private String getComment(final Field field) {
		final Comment annotation = field.getAnnotation(Comment.class);
		return annotation == null ? null : annotation.value();
	}

	// 取自定义注解值
	private int getOrder(final Field field) {
		final Order annotation = field.getAnnotation(Order.class);
		return annotation == null ? 0 : annotation.value();
	}

}
